package model;
import entity.TableRecord;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Restrictions;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.HibernateUtil;
import util.TableRecordBuilder;

import java.io.PrintWriter;
//import java.util.LinkedList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
 * Manager reads a next row from table and
 * submits a new thread Handler, passing
 * Message *to* this thread and taking a Reply *from*
 * to record in the third column of the corresponding
 * row table.
 */



public class Manager implements Runnable {
    private Logger logger = LoggerFactory.getLogger(Manager.class);

    private final int MAX_RESULTS = 100;

    // Hibernate session
    private Session session;

    private List<TableRecord> getRecords() {
        List<TableRecord> records = null;
        try {
            session = HibernateUtil.getSessionFactory().openSession();
            logger.info("Hibernate session was opened, trying to get data from DB.");
//            List<TableRecord> messages = session.createSQLQuery("SELECT * FROM messagestable WHERE status = 'new'")
//                    .addEntity(TableRecord.class).list();

            //List<TableRecord> messages = (List<TableRecord>)session.createQuery("FROM TableRecord ").list();

            session.beginTransaction();
            logger.info("Data obtaining transaction started.");

            // obtaining data
            Criteria criteria = session.createCriteria(TableRecord.class)
                    .add(Restrictions.like("status", "new"));
            criteria.setMaxResults(MAX_RESULTS);
            records = criteria.list();

            session.getTransaction().commit();
            logger.info("Data obtaining transaction committed.");

        } catch (Exception ex) {
            logger.error("Error occured", ex);
            throw new RuntimeException(ex);
        } finally {
            if(session != null  && session.isOpen()) {
                session.close();
            }
        }

        // updating status in the list of records
        ListIterator<TableRecord> iterator = records.listIterator();
        while (iterator.hasNext()) {
            TableRecord record = iterator.next();
            TableRecordBuilder builder = new TableRecordBuilder();
            builder.clone(record);
            builder.addStatus("processing");
            record = builder.getTableRecord();
            iterator.set(record);
        }

        try {
            session = HibernateUtil.getSessionFactory().openSession();

            // updating status of obtained records in DB
            session.beginTransaction();
            logger.info("Status updating transaction started.");

            for(TableRecord record : records) {
                session.update(record);
            }
            session.getTransaction().commit();
            logger.info("Status updating transaction committed.");

        } finally {
            if(session != null  && session.isOpen()) {
                session.close();
            }
        }

        return records;


    }

    @Override
    public void run() {
        logger.info("Inside Manager!");

        List<TableRecord> messages;
        ExecutorService exec = Executors.newCachedThreadPool();
        while(true) {
            messages = getRecords();
            logger.info("Records from table were got.");
            if(messages.size() < 1) {
                logger.info("All records from table were read.");
                break;
            }

            Handler handler = new Handler(messages);

            exec.submit(handler);
            logger.info("Handler submitted!");
        }
    }
}
